/**
 * @file    bsp_sd_diskio.c
 * @brief   SD卡FatFs驱动接口
 * @author  H743-V2飞控开发团队
 * @date    2024-11-08
 * @note    位置: Drivers/BSP/bsp_sd_diskio.c
 *
 * @details 实现FatFs需要的底层SD卡驱动接口
 *          使用HAL库的SDMMC驱动
 */

#include "ff_gen_drv.h"
#include "bsp_sd_diskio.h"
#include "main.h"
#include <string.h>

/* SD卡句柄 */
SD_HandleTypeDef hsd1;

/* 私有函数原型 */
static DSTATUS SD_CheckStatus(BYTE lun);

/* Diskio接口函数 */
DSTATUS SD_initialize(BYTE);
DSTATUS SD_status(BYTE);
DRESULT SD_read(BYTE, BYTE*, DWORD, UINT);
DRESULT SD_write(BYTE, const BYTE*, DWORD, UINT);
DRESULT SD_ioctl(BYTE, BYTE, void*);

/* Diskio驱动结构体 */
const Diskio_drvTypeDef SD_Driver =
{
    SD_initialize,
    SD_status,
    SD_read,
    SD_write,
    SD_ioctl,
};

/**
 * @brief  初始化SD卡
 * @param  lun: 逻辑单元号(未使用)
 * @retval DSTATUS: 操作状态
 */
DSTATUS SD_initialize(BYTE lun)
{
    (void)lun;
    DSTATUS stat = STA_NOINIT;
    
    /* 配置SDMMC1 GPIO */
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    /* 使能GPIO时钟 */
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();
    
    /* 配置SDMMC1引脚:
     * PC8  - SDMMC1_D0 (AF12, 上拉)
     * PC9  - SDMMC1_D1 (AF12, 上拉)
     * PC10 - SDMMC1_D2 (AF12, 上拉)
     * PC11 - SDMMC1_D3 (AF12, 上拉)
     * PC12 - SDMMC1_CK (AF12, 无上拉)
     * PD2  - SDMMC1_CMD (AF12, 上拉)
     */

    /* 配置数据线D0-D3 (需要上拉) */
    GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* 配置时钟线CK (无上拉) */
    GPIO_InitStruct.Pin = GPIO_PIN_12;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* 配置命令线CMD (需要上拉) */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    
    /* 使能SDMMC1时钟 */
    __HAL_RCC_SDMMC1_CLK_ENABLE();
    
    /* 配置SDMMC1 */
    hsd1.Instance = SDMMC1;
    hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
    hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
    hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B;
    hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
    /* 时钟分频：PLL1_Q = 240MHz
     * 传输时钟 = 240MHz / (2 * (ClockDiv + 1))
     * ClockDiv = 5 → 传输时钟 = 240MHz / 12 = 20MHz (参考固件推荐值)
     * 初始化时钟由HAL库自动配置为400kHz
     */
    hsd1.Init.ClockDiv = 5;
    
    /* 初始化SD卡 */
    HAL_StatusTypeDef hal_status = HAL_SD_Init(&hsd1);
    if (hal_status == HAL_OK)
    {
        stat = SD_CheckStatus(lun);
    }
    else
    {
        /* 初始化失败，输出错误信息 */
        extern void debug_printf(const char *format, ...);
        debug_printf("[SD] HAL_SD_Init failed: %d\r\n", hal_status);
        debug_printf("[SD] Error code: 0x%08lX\r\n", hsd1.ErrorCode);
    }

    return stat;
}

/**
 * @brief  获取SD卡状态
 * @param  lun: 逻辑单元号(未使用)
 * @retval DSTATUS: 磁盘状态
 */
DSTATUS SD_status(BYTE lun)
{
    return SD_CheckStatus(lun);
}

/**
 * @brief  从SD卡读取扇区
 * @param  lun: 逻辑单元号(未使用)
 * @param  buff: 数据缓冲区
 * @param  sector: 扇区地址(LBA)
 * @param  count: 扇区数量
 * @retval DRESULT: 操作结果
 */
DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{
    (void)lun;
    DRESULT res = RES_ERROR;
    uint32_t timeout = 100000;
    
    if (HAL_SD_ReadBlocks(&hsd1, buff, sector, count, timeout) == HAL_OK)
    {
        /* 等待传输完成 */
        while (HAL_SD_GetCardState(&hsd1) != HAL_SD_CARD_TRANSFER)
        {
            if (timeout-- == 0)
            {
                return RES_ERROR;
            }
        }
        res = RES_OK;
    }
    
    return res;
}

/**
 * @brief  向SD卡写入扇区
 * @param  lun: 逻辑单元号(未使用)
 * @param  buff: 数据缓冲区
 * @param  sector: 扇区地址(LBA)
 * @param  count: 扇区数量
 * @retval DRESULT: 操作结果
 */
DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
    (void)lun;
    DRESULT res = RES_ERROR;
    uint32_t timeout = 100000;
    
    if (HAL_SD_WriteBlocks(&hsd1, (uint8_t*)buff, sector, count, timeout) == HAL_OK)
    {
        /* 等待传输完成 */
        while (HAL_SD_GetCardState(&hsd1) != HAL_SD_CARD_TRANSFER)
        {
            if (timeout-- == 0)
            {
                return RES_ERROR;
            }
        }
        res = RES_OK;
    }
    
    return res;
}

/**
 * @brief  I/O控制操作
 * @param  lun: 逻辑单元号(未使用)
 * @param  cmd: 控制命令
 * @param  buff: 发送/接收控制数据的缓冲区
 * @retval DRESULT: 操作结果
 */
DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff)
{
    (void)lun;
    DRESULT res = RES_ERROR;
    HAL_SD_CardInfoTypeDef CardInfo;
    
    if (HAL_SD_GetCardState(&hsd1) == HAL_SD_CARD_TRANSFER)
    {
        res = RES_OK;
        
        switch (cmd)
        {
        /* 确保设备已完成写入 */
        case CTRL_SYNC:
            res = RES_OK;
            break;
        
        /* 获取扇区数量 */
        case GET_SECTOR_COUNT:
            HAL_SD_GetCardInfo(&hsd1, &CardInfo);
            *(DWORD*)buff = CardInfo.LogBlockNbr;
            res = RES_OK;
            break;
        
        /* 获取扇区大小 */
        case GET_SECTOR_SIZE:
            HAL_SD_GetCardInfo(&hsd1, &CardInfo);
            *(WORD*)buff = CardInfo.LogBlockSize;
            res = RES_OK;
            break;
        
        /* 获取擦除块大小 */
        case GET_BLOCK_SIZE:
            HAL_SD_GetCardInfo(&hsd1, &CardInfo);
            *(DWORD*)buff = CardInfo.LogBlockSize / 512;
            res = RES_OK;
            break;
        
        default:
            res = RES_PARERR;
        }
    }
    
    return res;
}

/**
 * @brief  检查SD卡状态
 * @param  lun: 逻辑单元号(未使用)
 * @retval DSTATUS: 磁盘状态
 */
static DSTATUS SD_CheckStatus(BYTE lun)
{
    (void)lun;
    DSTATUS stat = STA_NOINIT;
    
    if (HAL_SD_GetCardState(&hsd1) == HAL_SD_CARD_TRANSFER)
    {
        stat &= ~STA_NOINIT;
    }
    
    return stat;
}

